LBB

如何实现 Dark Mode

# 如何实现 Dark Mode ## 实现 ### Step1. 通过 CSS 媒体查询的 [prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) 功能来检测用户系统或代理的偏好设置 用户没有手动设置过 theme 时,theme 应该自动根据用户系统或代理的偏好进行切换。 ```css :root { --color-font: #333; } @media (prefers-color-scheme: dark){ :root{ --color-font: #fff; } } ``` ### Step2. 设置 class 覆盖用户系统或代理的偏好设置 当用户手动点击网页上的切换主题以后,使用自定义的 class 覆盖 @media 查询的用户系统偏好。并将用户主动选择的 theme 记录到 localStorage 中。 ```css .light{ --color-font: #333; } .dark{ --color-font: #fff; } <body class="dark"></body> ``` ### Step3. 在页面内容加载前,检测用户本地 localStorage 中的 theme 设置 避免用户手动设置的 theme 与用户系统或代理的偏好设置不一致,导致页面在第一次加载时 theme 被覆盖导致的抖动。 ```html <html> <body> <script> ;(() => { const preference = localStorage.getItem('${APPEARANCE_KEY}') || '${fallbackPreference}' const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches if (!preference || preference === 'auto' ? prefersDark : preference === 'dark') document.documentElement.classList.add('dark') })() </script> </body> </html> ``` ## FAQ ### 为什么 React、Vue、Svelet 都使用 localStorage 存储 theme,而不是用 cookie 呢? 看了一下 React、Vue、Svelet 官网的主题实现,发现他们都将 theme 存储在 localStorage 中,然后在 html 中靠前的位置插入一段检测 localStorage 的中 theme 的代码,从而避免水合不一致的问题。为什么不使用 cookie 呢?这样就可以在服务端 SSR 的时候获取到用户的配置了。 我个人认为,可能有以下原因: - Cookie 会带到每个请求中造成不必要的浪费,也可能有一定的安全考虑 - Cookie 存储的时间有限,可能会因为用户清空缓存导致失效 - 根据 GDPR 法案的政策,使用 cookie 存储信息,即使是用户的偏好设置,不用与收集的目的也要告知和提示 (我觉得这个可能是最重要的,Meta 和 Goolge 似乎都因此被开出过天价罚单) (https://github.com/vuejs/vitepress/blob/d3dd4bc93806f3bc7be5f29ad279978b4fd13c81/src/node/config.ts#L282) (https://github.com/reactjs/react.dev/blob/db2dc7f9875f00688cd6ffc511abf5849c21952a/src/pages/_document.tsx#L37) (https://github.com/sveltejs/svelte/blob/d5776c3ec38b98659081d21f3cd93960ebfddb91/sites/svelte.dev/src/app.html#L34)
如何实现 Dark Mode | LBB